package remote;

import infrastructure.exceptions.SessionException;

import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import authentication.AuthenticationManager;

import dal.User;

import remote.Session.SessionId;

/**
 * This class is responsible for managing the sessions with the server.
 * This class is thread safe, so any number of processes can 
 * share it
 * @author sashas
 *
 */
public class SessionManager {
	
	/** Keeps list of active sessions on the server*/
	ConcurrentHashMap<Session.SessionId,Session> sessions;
	
	/** Represents guest session*/
	private static Session GUEST_SESSESSION= new Session(new SessionId(0),
			AuthenticationManager.getInstance().getGuestUser());

	/** Keeps instance of the session manager*/
	private static SessionManager theInstance = new SessionManager();
	
	/** Keeps randomizer for session creation*/
	Random sessionRandomizer = new Random();
	
	
	private SessionManager(){
		sessions = new ConcurrentHashMap<Session.SessionId, Session>();
		sessions.put(GUEST_SESSESSION.getSessionID(), GUEST_SESSESSION);
	}
	
	
	public boolean isSessionExists(SessionId id){
		return sessions.containsKey(id);
	}
	
	
	public Session getSession(SessionId id) throws SessionException{
		Session serverSession = sessions.get(id);
		if (null != serverSession){			
			return serverSession;
		}else{
			throw new SessionException("Session does not exists");
		}
	}
	

	public Session createSession(User user){
		
		Session newSession;
		Session currentSession;
		do{
			long sessionId = (sessionRandomizer.nextLong() & Long.MAX_VALUE);
			Session.SessionId newId = new Session.SessionId(sessionId);
			newSession = new Session(newId,user);
			currentSession = sessions.putIfAbsent(newId,newSession);	
		}while(null != currentSession);
		
		return newSession;
	}
	
	public void deleteSession(Session.SessionId id){		
		
		// Check that this is not the guest session that is deleted 
		if (!id.equals(getGuestSession().getSessionID())){
			sessions.remove(id);
		}
		
	}
	
	
	public static SessionManager getInstance(){
		return theInstance;
	}
	
	public static Session getGuestSession(){
		return GUEST_SESSESSION;
	}
	
}
